#ifndef THREADSAFETRIANGLE_H_
#define THREADSAFETRIANGLE_H_

#include "triangle.h"
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>

/*!
 * Triangulo con bloqueos para exclusion mutua de threads
 */
class ThreadSafeTriangle : public Triangle
{
	/*!
	 * Imprime ThreadSafeTriangle en el mismo formato que Triangle
	 */
friend std::ostream& operator<< (std::ostream& out, const ThreadSafeTriangle& t);

protected:
	/*!
	 * Arreglo con punteros a los triangulos thread safe vecinos
	 */
	ThreadSafeTriangle* neighbors[3];
	/*!
	 * Mutex para trabajo con memoria compartida
	 */
	mutable QMutex mutex;
	/*!
	 *  Mutex que protege la informacion interna
	 */
	mutable QMutex internalMutex;
	/*!
	 * Condicion de espera a que cambie un elemento del arreglod e vecinos
	 */
	QWaitCondition neighborChanged;
	/*!
	 * Constructor Prohibido
	 */
	ThreadSafeTriangle();
	/*!
	 * Revisa la integridad
	 */
	bool invariante() const;
public:
	/*!
	 * Constructor basico
	 */
	ThreadSafeTriangle(const Triangle &t);
	/*!
	 * Constructor por copia
	 */
	ThreadSafeTriangle(ThreadSafeTriangle &t);
	/*!
	 * Destructor
	 */
	virtual ~ThreadSafeTriangle();
	/*!
	 * Obtiene el Id del triangulo
	 */
	int getId() const;
	/*!
	 * Establece el ID del triangulo
	 */
	void setID(int _id);
	/*!
	 * Crea una nueva arista i. i>-1 y <4. Recordar destruir la arista.
	 */
	Edge getEdge(int i) const;
	/*!
	 * Chequea que la arista exista dentro del triangulo fijandose en los ids
	 * de los vertices
	 */
	bool hasEdge(const Edge *e) const;
	/*!
	 * Obtiene el vertice i. i>-1 y <4
	 */
	Vertex* getVertex(int i) const;
	/*!
	 * Devuelve el indice de la arista mas larga.
	 */
	int longestEdgeIndex() const;
	/*!
	 * Establece los triangulos vecinos. Se espera que cada triangulo comparta una arista (y dos vertices).
	 * Los triangulos corresponden a los vertices, asi el triangulo vecino i esta opuesto al vertice i.
	 */
	void setNeighbors(ThreadSafeTriangle *t1,ThreadSafeTriangle *t2, ThreadSafeTriangle *t3);
	/*!
	 * establece el vecino por la arista con indice i
	 */
	void setNeighbor(int i, ThreadSafeTriangle *t);
	/*!
	 * Busca al vecino objective y lo reemplaza. Si no lo encuentra lanza una assertion
	 */
	void replaceNeighbor(ThreadSafeTriangle *objective,ThreadSafeTriangle *replacement);
	/*!
	 * Obtiene el Triangulo vecino opuesto al vertice ingresado
	 */
	ThreadSafeTriangle * getNeighborOposedToVertex(Vertex *v) const;
	/*!
	 * Obtiene el angulo del vertice i.
	 */
	Angle getAngle(int i) const;
	/*!
	 * Imprime la representacion del triangulo
	 */
	std::string toString() const;
	/*
	 * devuelve un puntero al mutex de este triangulo
	 */
	QMutex * getMutex();
	/*!
	 * Obtiene el Triangulo vecino por el indice de la arista edge_index. A diferencia de
	 * getNeighbor(int) este metodo primero intentara bloquear el acceso al triangulo vecino
	 * y modificara el estado del mutex neighborMutex() de este triangulo
	 */
	ThreadSafeTriangle *getNeighbor(int edge_index);
};

#endif /*THREADSAFETRIANGLE_H_*/
